package main;

import java.awt.Color;
import java.awt.Container;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.sound.midi.*;
import javax.sound.midi.MidiDevice.*;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

import library.*;
import model.*;
import view.*;
/**CONTROLLER**/
public class JMIDI implements ActionListener, MouseListener, FocusListener, PropertyChangeListener, KeyListener
{
	private MidiDevice[] device;
	private CueStack stack;
	private Workspace wWindow;
	private CueCreator cWindow;
	private GoWindow goWindow = new GoWindow(this);

	public static void main(String[] args)
	{
		JMIDI main = new JMIDI();
	}

	public JMIDI()
	{
		this.setupInterface();
		device = new MidiDevice[2];
		stack = new CueStack();
		open();
	}

	public void setupInterface()
	{
		wWindow = new Workspace(this);
		wWindow.setVisible(true);
	}

	private void open() 
	{
		MidiDevice.Info[] systemInfo = MidiSystem.getMidiDeviceInfo();
		MidiDevice in = null;
		MidiDevice out = null;
		try {
			ArrayList<MidiDevice> devices = getUnoDevices(systemInfo);
			in = devices.get(0);
			out = devices.get(1);
		} catch(Exception e) {
			System.out.println("1");
			JOptionPane.showMessageDialog(wWindow, "No Midi Device found. Please restart.", "Error!",
					JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		try {
			in.open();
			out.open();
		} catch (MidiUnavailableException e) {
			System.out.println("2");
			JOptionPane.showMessageDialog(wWindow, "Midi Error", "Error!", 
					JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		device[0] = in;
		device[1] = out;
	}

	@Override
	public void actionPerformed(ActionEvent event)
	{
		String actionCommand = event.getActionCommand();
		Object source = event.getSource();

		if(actionCommand.equals("GO"))
		{
			//if(!isOpen())
				//open();
			stack.fire(stack.load(), getReceiver());
		}
		else if(actionCommand.equals("CueCreator OK!"))
		{
			String[] newCueInfo = this.getCueCreatorInfoAndDispose();
			String[] info = this.getCueCreatorInfoAndDispose();
			CueFactory factory = null;
			if(info[0].equals("Audio"))
				factory = new AudioFactory();
			else
				factory = new ExpressFactory();

			Cue cue = factory.build(info);
			stack.add(cue);
			wWindow.addCue(newCueInfo);
			wWindow.setNumCuesLabel(stack.size());
		}
		else if(actionCommand.equals("Create Cue"))
		{
			this.showCueBuilder();
		}
		else if(actionCommand.equals("Cue Type"))
		{
			if(((JComboBox) source).getSelectedItem().equals("Audio"))
				cWindow.changeOptions("Audio");
			else if(((JComboBox) source).getSelectedItem().equals("MSC"))
				cWindow.changeOptions("MSC");
		}
		else if(actionCommand.equals("CC file browser"))
		{
			cWindow.selectFile();
		}
		else if(actionCommand.equals("Create Cue"))
		{
			this.showCueBuilder();
		}
		else if(actionCommand.equals("Cue Type"))
		{
			if(((JComboBox) source).getSelectedItem().equals("Audio"))
				cWindow.changeOptions("Audio");
			else if(((JComboBox) source).getSelectedItem().equals("MSC"))
				cWindow.changeOptions("MSC");
		}
		else if(actionCommand.equals("timerUp"))
		{
			wWindow.slideInspector(false);
		}
		else if(actionCommand.equals("timerDown"))
		{
			wWindow.slideInspector(true);
		}
		else if(actionCommand.equals("Switch to Workspace"))
		{
			goWindow.setVisible(false);
			wWindow.setVisible(true);	
		}
		else if(actionCommand.equals("Switch to Simple"))
		{
				wWindow.setVisible(false);
				goWindow.setVisible(true);
		}
		else if(actionCommand.equals("Simple Go"))
		{
			String text = goWindow.getText();
			System.out.println(text);
			goWindow.clearText();
			ExpressQ cue = new ExpressQ("temp");
			try {
				cue.setMessage(Integer.parseInt(text));
			} catch (NumberFormatException e) {
				System.out.println("pie");
				e.printStackTrace();
			} catch (InvalidMidiDataException e) {
				System.out.println("pie");
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("fired");
			Receiver temp = getReceiver();
			temp.send(cue.getMessage(), -1);
		}
		else if(actionCommand.equals("Delete"))
		{
			wWindow.delete();
		}
		else if(actionCommand.equals("Move Up"))
		{
			
		}
	}
	@Override
	public void mousePressed(MouseEvent e) {
		Object source = e.getSource();

		if(source instanceof CuePanel)
		{
			CuePanel temp = (CuePanel) source;

			if(wWindow.isSomethingSelected())
			{
				StringBuilder writtenNotes = new StringBuilder(wWindow.getNotes());
				stack.setNote(writtenNotes);
			}

			wWindow.unselect();
			stack.select(Integer.parseInt(temp.getCueNumber()));
			wWindow.select((CuePanel) source, stack.displayNote());
		}
		else if(source instanceof OptionPanel)
		{
			String option = ((OptionPanel) source).getOptionType();
			if(option.equals("Inspector"))
				wWindow.initiateInspectorSlide();
			else if(option.equals("Stop All"))
				stack.stopAll();

			String originalFile = ((ImageIcon) ((OptionPanel) source).getOutputLabel().getIcon()).getDescription();
			originalFile = originalFile.substring(0, originalFile.indexOf('.'));
			String newFile = originalFile + " Dark.png";
			((OptionPanel) source).getOutputLabel().setIcon(new ImageIcon(newFile));
		}
		else if (source instanceof TexturedPanel)
		{
			if(wWindow.isSomethingSelected())
			{
				StringBuilder writtenNotes = new StringBuilder(wWindow.getNotes());
				stack.setNote(writtenNotes);
			}
			wWindow.unselect();
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {}

	@Override
	public void mouseReleased(MouseEvent e) {
		try
		{
			Object source = e.getSource();
			if(source instanceof OptionPanel)
			{
				String option = ((OptionPanel) source).getOptionType();
				String originalFile = ((ImageIcon) ((OptionPanel) source).getOutputLabel().getIcon()).getDescription();
				originalFile = originalFile.substring(0, originalFile.indexOf(" Dark"));
				String newFile = originalFile + ".png";
				((OptionPanel) source).getOutputLabel().setIcon(new ImageIcon(newFile));
			}
		}
		catch(Exception ex) {}

	}

	@Override
	public void mouseEntered(MouseEvent e) {

	}
	@Override
	public void mouseExited(MouseEvent e) 
	{
		try
		{
			Object source = e.getSource();
			if(source instanceof OptionPanel)
			{
				String option = ((OptionPanel) source).getOptionType();
				String originalFile = ((ImageIcon) ((OptionPanel) source).getOutputLabel().getIcon()).getDescription();
				originalFile = originalFile.substring(0, originalFile.indexOf(" Clicked"));
				String newFile = originalFile + ".png";
				((OptionPanel) source).getOutputLabel().setIcon(new ImageIcon(newFile));
			}
		}
		catch(Exception ex) {}
	}


	@Override
	public void focusGained(FocusEvent e)
	{
		Object source = e.getSource();
		if(source instanceof JFormattedTextField)
		{
			((JFormattedTextField) source).setForeground(Color.BLACK);
			((JFormattedTextField) source).setText("");
		}
	}

	@Override
	public void focusLost(FocusEvent e) 
	{

	}

	@Override
	public void propertyChange(PropertyChangeEvent evt)
	{
		String propertyName = evt.getPropertyName();
		Object source = evt.getSource();

		if(propertyName.equals("dividerLocation"))
		{	
			int oldVal = (int) evt.getOldValue();
			int newVal = (int) evt.getNewValue();

			if(newVal == 93 && newVal < oldVal)
				wWindow.hideItem((JComponent) ((Container) source).getComponent(0));
			else if(newVal < 92 && newVal != 0)
				wWindow.displayItem((JComponent) ((Container) source).getComponent(0), (JSplitPane) source);
		}

	}

	@Override
	public void keyTyped(KeyEvent e)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void keyReleased(KeyEvent e)
	{
		// TODO Auto-generated method stub

	}

	private Receiver getReceiver() {
		Receiver ups;
		try {
			ups = device[1].getReceiver();
		} catch (MidiUnavailableException e) {
			System.out.println("3");
			JOptionPane.showMessageDialog(wWindow, "Midi Error", "Error!", 
					JOptionPane.ERROR_MESSAGE);
			return null;
		} catch (NullPointerException e) {
			return null;
		}
		return ups;
	}
	private static ArrayList<MidiDevice> getUnoDevices(Info[] info) 
	{
		ArrayList<MidiDevice> devices = new ArrayList<MidiDevice>();
		/**for(Info i : info)
		{
			if(i.getName().contains("2x2"))
			{
				try {
					devices.add(MidiSystem.getMidiDevice(i));
				} catch (MidiUnavailableException e) {
					e.printStackTrace();
				}
			}
		}**/
		try {
			devices.add(MidiSystem.getMidiDevice(info[1]));
		} catch (MidiUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			devices.add(MidiSystem.getMidiDevice(info[5]));
		} catch (MidiUnavailableException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return devices;
	}

	public void showCueBuilder() {
		cWindow = new CueCreator(this);
		cWindow.setVisible(true);
	}

	public String[] getCueCreatorInfoAndDispose()
	{
		String[] output = cWindow.getFormInfo();
		cWindow.dispose();
		return output;
	}

	public void displayError(String message)
	{
		JOptionPane.showMessageDialog(wWindow, message);
	}
	private boolean isOpen()
	{
		if(device[0].isOpen() && device[1].isOpen())
			return true;
		return false;
	}
}
